var user = {}
var config = {
    // bundlePolicy: 'max-bundle',
    // bundlePolicy: 'balanced',
    iceTransportPolicy: 'all',
    // rtcpMuxPolicy: 'require',
    // iceCandidatePoolSize: 1,
    iceServers: [
        {
            urls: 'stun:stun.intervoip.com:3478'
            // urls: 'stun:stun.l.google.com:19302'
        }
    ]
}

var target = ''
var websocketServer = null
var messageUtil = null

$(document).ready(function () {
    window.onbeforeunload = function(ev){
        if(this.websocketServer != null){
            this.websocketServer.close()
        }
    }
    websocketServer = new websock()

    $('#username').change(function (e) {
        user.username = $(this).val()
    })
    $('#login').click((e)=>{
        console.log(websocketServer)
        if(websocketServer.connected){
            websocketServer.send({
                'type': 'login',
                'username': user.username
            })
        } 
    })
    $('#target').change(function (e) {
        target = $(this).val()
    })
    $('#connect').click(function (e) { 
        websocketServer.initOffer(target)
    })
    $('#send').click(function (e) { 
        websocketServer.connections[0].peerConnection.channel.send({type: 'message', data: 'hi'})
    })
});

function createChannel(connectId, param){
    var channel = new Channel(param)
    
    return channel
}


async function createPeer(connectId, channelFunc, localDescription, remoteDescription){
    var pc = new RTCPeerConnection(config)
    pc.candidates = []
    pc.ondatachannel = (ev) => {
        channelFunc(connectId, ev.channel)
        pc.channel = channel
        pc.channel.send({type: 'hand'})
        // 连接成功  
    }
    if(channelFunc !== null){
        var channel = channelFunc(connectId, pc.createDataChannel(connectId))
        pc.channel = channel
    }
    
    pc.ontrack = (ev) => {
        console.log(ev)
    }
    pc.oniceconnectionstatechange = (ev)=>{
        console.log(ev)
        console.log(pc.iceConnectionState)
        // if(offerPeer.iceConnectionState === 'connected'){
            
        // }
        
    }
    pc.onicecandidateerror = (err)=>{
        // console.log('onicecandidateerror: ' + JSON.stringify(err))
        // console.log(err)
    }

    // 这两步必须
    remoteDescription(pc)
    localDescription(pc)

    return pc
}



async function createOfferPeer(connectId){
    return await createPeer(connectId, createChannel, async (pc)=>{
        const offerOptions = {offerToReceiveAudio: 1}
        var desc = await pc.createOffer(offerOptions)
        pc.setLocalDescription(desc)
    }, (pc)=>{
        // offer端加入remoteDescription回调等待服务器返回对方信息
        pc.remoteDescriptionCallback = (remoteDescription, candidates, pc)=>{
            pc.setRemoteDescription(remoteDescription)
            for(var i = 0; i < candidates.length; ++i){
                pc.addIceCandidate(candidates[i])
            }
        }
    })

}

async function createAnswerPeer(connectId, offer, candidates){
    return await createPeer(connectId, createChannel, async (pc)=>{
        const answerOption = {
            offerToReceiveAudio: true,
            offerToReceiveVideo: true,
        }
        var desc = await pc.createAnswer(answerOption)
        pc.setLocalDescription(desc)
        for(var temp in candidates){
            pc.addIceCandidate(candidates[temp])
        }
    }, (pc)=>{
        pc.setRemoteDescription(offer)
    })
}

class Channel{
    constructor(channel){
        this.channel = channel
        this.channel.onopen = (ev)=>{
            console.log('onopen: ' + JSON.stringify(ev))
        }
        this.channel.onmessage = (ev)=>{
            var data = JSON.parse(ev.data)
            this.deal(data)
        }
        this.channel.onclose = (ev)=>{
            console.log('onclose: ' + JSON.stringify(ev))
        }
        this.channel.onerror = (ev)=>{
            console.log('onerror: ' + JSON.stringify(ev))
        }
    }

    send(data){
        this.channel.send(JSON.stringify(data))
    }

    deal(data){
        switch (data.type){
            case 'hand':
                this.send({type: 'handReceive'})
                break
            case 'handReceive':
                websocketServer.send({type: 'connected', connectId: this.channel.label})
                console.log('handReceive')
                break
            case 'message':
                console.log(data.data)
                break
            default:
                break

        }
    }
}

class websock{
    constructor() {
        this.ws = this.createWebsocket(this)
        this.connected = false
        this.user = user
        this.connections = []
    }
    createWebsocket(that){
        var ws = new WebSocket("ws://localhost:9001")
        ws.onopen = function(){
            // 当WebSocket创建成功时，触发onopen事件
            console.log("open")
            that.connected = true
            console.log(that.connected)
            // tap()
            // ws.send("hello"); //将消息发送到服务端
        }
        ws.onmessage = function(e){
            // 当客户端收到服务端发来的消息时，触发onmessage事件，参数e.data包含server传递过来的数据
            that.deal(JSON.parse(e.data))
        }
        ws.onclose = function(e){
            // 当客户端收到服务端发送的关闭连接请求时，触发onclose事件
            console.log("close")
            this.close()
        }
        ws.onerror = function(e){
            // 如果出现连接、处理、接收、发送数据失败的时候触发onerror事件
            console.log(e)
            this.close()
        }
        return ws
    }

    initOffer(target){
        this.send({type: 'initOffer', user: user, target: target})
    }

    async createOfferAndSendMessage(connectId){
        // createOfferPeer(connectId).then(pc=>{
        //     this.connections.push({connectId: connectId, peerConnection: pc})
        //     console.log ('push')
        //     this.send({type: 'connect', offer: pc.localDescription, candidates: pc.candidates, connectId: connectId})
        // })
        // TODO pc.localDescription为空   pc.candidates为空
        var pc = await createOfferPeer(connectId)
       
        pc.onicecandidate = async (ev) => {
            if(ev.candidate){
                console.log('------------------------------')
                console.log('address: ' + ev.candidate.address)
                console.log('port: ' + ev.candidate.port)
                console.log('protocol: ' + ev.candidate.protocol)
                console.log('type: ' + ev.candidate.type)
                console.log('usernameFragment: ' + ev.candidate.usernameFragment)
                // offerPeer.addIceCandidate(ev.candidate)
                if(ev.candidate.type === 'srflx'){
                    pc.candidates.push(ev.candidate)
                    if(pc.candidates.length > 1){
                        this.send({type: 'connect', offer: pc.localDescription, candidates: pc.candidates, connectId: connectId})
                    }
                    
                }
                console.log('------------------------------')
            }
        }
        this.connections.push({connectId: connectId, peerConnection: pc})
        
    }

    async createAnswerAndSendMessage(connectId, offer, candidates){
        var pc = await createAnswerPeer(connectId, offer, candidates)
        pc.onicecandidate = async (ev) => {
            if(ev.candidate){
                console.log('------------------------------')
                console.log('address: ' + ev.candidate.address)
                console.log('port: ' + ev.candidate.port)
                console.log('protocol: ' + ev.candidate.protocol)
                console.log('type: ' + ev.candidate.type)
                console.log('usernameFragment: ' + ev.candidate.usernameFragment)
                // offerPeer.addIceCandidate(ev.candidate)
                pc.candidates.push(ev.candidate)
                this.send({type: 'answerConnect', answer: pc.localDescription, candidates: pc.candidates, connectId: connectId})
                if(ev.candidate.type === 'srflx'){
                   
                }
                console.log('------------------------------')
            }
        }
        this.connections.push({connectId: connectId, peerConnection: pc})
    }

    send(param){
        this.ws.send(JSON.stringify(param))
    }

    close(){
        this.ws.close()
        this.connected = false
    }

    findConnectionByConnectId(connectId){
        for(var i = 0; i < this.connections.length; ++i){
            if(this.connections[i].connectId === connectId){
                return this.connections[i]
            }
        }
        return null
    }

    async deal(data){
        switch (data.type) {
            case 'loginResponse':
                if(data.code == 200){
                    user.id = data.id
                }else{
                    console.log('失败')
                }
                break
            case 'getOffer':
                this.createAnswerAndSendMessage(data.connectId, data.offer, data.candidates)
                console.log(data)
                break
            case 'getAnswer':
                var connect = this.findConnectionByConnectId(data.connectId)
                if(connect != null){
                    connect.peerConnection.remoteDescriptionCallback(data.answer, data.candidates,connect.peerConnection)
                }
                break
            case 'initOfferResponse':
                if(data.code === 200){
                    this.createOfferAndSendMessage(data.connectId)
                }else if(data.code === 404){
                    console.log('no target')
                }
                break
            default:
                break
        }
    }
}